Skip to content

chore: implement storybook#932

Open
jakehwll wants to merge 77 commits intomainfrom
jakehwll/implement-storybook
Open

chore: implement storybook#932
jakehwll wants to merge 77 commits intomainfrom
jakehwll/implement-storybook

Conversation

@jakehwll
Copy link
Copy Markdown

@jakehwll jakehwll commented May 4, 2026

This PR was modified by Coder Agents on behalf of Jake Howell.

Adds Storybook support for developing and previewing webview components in isolation outside of VS Code. Includes stories for all tasks package components with a dark/light theme switcher that mirrors VS Code CSS custom properties.

  • Add .storybook/ config with Vite integration, workspace alias resolution, codicon injection, and acquireVsCodeApi mock
  • Add dark-v2 and light-v2 themes (sourced from vscode-elements/webview-playground) with a toolbar switcher in globalTypes
  • Add 17 component stories under packages/tasks/src/components/ covering all major UI states
  • Add test/webview/decorators.tsx with a shared withQueryClient decorator for stories using React Query
  • Add storybook and build-storybook scripts to root package.json
  • Add Storybook dependencies to workspace catalog

Comment thread package.json Outdated
Comment thread package.json Outdated
Comment thread .storybook/tsconfig.json
Comment thread .storybook/tsconfig.json Outdated
Comment thread .storybook/tsconfig.json Outdated
Comment thread .storybook/preview.ts Outdated
Comment thread .storybook/preview.ts Outdated
Comment on lines +1 to +2
// Sourced from `vscode-elements/webview-playground`.
// https://github.com/vscode-elements/webview-playground/blob/f9a6f90413d0cc535839fb92445b7a5eebc540d7/dist/themes/dark-v2.js
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid manual refreshes, add a scripts/sync-vscode-themes.mjs that fetches both files from the pinned upstream sha (already in the header comments) and rewrites them in place

I'm not sure if this would work but can we have the script filter vars referenced in our source plus those used by @vscode-elements/elements, which would cut these files by ~85% (though it's only a big change on this branch only)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it points to the same SHA why do we want to pull it again? Am I missing something? 🙂

I think the script filter might be a future improvement

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to say that we can trigger this script and it would pull a new SHA (most recent) and add that comment in the header so we know what upstream SHA we are currently pinned against

Comment thread packages/storybook-utils/src/decorators/withQueryClient.tsx Outdated
Comment thread .storybook/preview.ts Outdated
@EhabY
Copy link
Copy Markdown
Collaborator

EhabY commented May 5, 2026

Love the change and the story books ❤️

Pls do run the linters and make sure the pipeline passes!

jakehwll added 16 commits May 6, 2026 11:56
Replace the tag-based dynamic CSS import in .storybook/preview.ts
with a withTasksStyles decorator exported from packages/tasks/src/decorators.ts.
Each tasks story opts in via its decorators array, keeping preview.ts
package-agnostic. Future packages can follow the same pattern.
pnpm workspace:* protocol and package.json exports fields handle
@repo/* resolution natively — the hand-rolled getWorkspaceAliases
function was redundant.
- Add react, @tanstack/react-query, and @storybook/react to
  storybook-utils package.json so it declares its own contracts.
- Rename setState param from T to state in preview.ts mock.
- Fix import ordering across story and test files (lint autofix).
- Add tsconfig.json for @repo/mocks and @repo/storybook-utils so
  eslint's project service can find them.
- Fix import ordering in mocks/tasks.ts and inbox.test.ts.
- Extract QueryClientDecorator component to satisfy rules-of-hooks.
- Sort devDependencies in tasks/package.json.
@jakehwll
Copy link
Copy Markdown
Author

jakehwll commented May 6, 2026

/coder-agents-review

Copy link
Copy Markdown

@coder-agents-review coder-agents-review Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All 23 DEREM findings are now resolved (21 fixed, 1 accepted with documentation, 1 contested then fixed after panel decision). The author addressed every item, including the contested DEREM-14 which was fixed in ee1d2a6 after the panel's 5/5 rejection of the original defense.

The PR has been substantially refactored based on @EhabY's architectural feedback (new @repo/storybook-utils package, restructured imports, per-package CSS decorators, removed getDefaultFontStack). Those changes are under active human review.

CI is still failing on Lint. Please ensure pnpm lint passes before merging.

No new findings from this round.

🤖 This review was automatically generated with Coder Agents.

jakehwll added 7 commits May 6, 2026 05:18
These blocks were accidentally added to package.json but belong
exclusively in pnpm-workspace.yaml. The duplicate workspaces field
used an object format that eslint-plugin-package-json rejected as
invalid (expects an array per npm spec).
Reverts e346f15. The --vscode-font-family CSS variable is only
referenced in global.css, not defined by the theme data. Without the
inline font stack the Storybook preview renders with browser defaults.
CollapsibleToggle and TaskSelection play functions relied on web
component attribute reflection and IPC side-effects that don't work
reliably in Chromatic's headless environment. The stories remain as
visual-only variants covering collapsed and expanded states.
@EhabY
Copy link
Copy Markdown
Collaborator

EhabY commented May 6, 2026

Now that we have storybooks, there seems to be some inconsistencies:

tasks-actionmenu--opened, the loading item is not aligned with the others:

image

tasks-errorbanner--default, should we align the view logs to the right?

image

tasks-statepanel--error, the retry here is not a button while it is a button in the error state. Was this intentional or a storybook styling issue 🤔?

image

The status indicators are not applying the right styles it seems, like this is just a pure square:

image

tasks-tasklist--default could mix and match other states and descriptions IMO for better coverage

image

This is the "Task Selection" test but I do not see it selecting a task (or inside a selected task):

image

Comment thread package.json
"@storybook/test": "catalog:",
"@storybook/addon-a11y": "^8.6.18",
"@storybook/addon-essentials": "^8.6.18",
"@storybook/react": "^8.6.18",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one could be moved back to the catalog now that we import it in an inner package actually

Comment on lines +1 to +2
// Sourced from `vscode-elements/webview-playground`.
// https://github.com/vscode-elements/webview-playground/blob/f9a6f90413d0cc535839fb92445b7a5eebc540d7/dist/themes/dark-v2.js
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to say that we can trigger this script and it would pull a new SHA (most recent) and add that comment in the header so we know what upstream SHA we are currently pinned against

* Injects the tasks package CSS into the Storybook preview.
* Add to `decorators` in any story that renders tasks components.
*/
export const withTasksStyles: Decorator = (Story) => Story();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The entire reason the file exists is to trigger import "../index.css" as a side effect when stories import the symbol. I would rather that we do not mix production utils in with test utils.

Replace with import.meta.glob in .storybook/preview.ts:

// packages/tasks/storybook.preview.ts
import "./src/index.css";
// .storybook/preview.ts
import.meta.glob("../packages/*/storybook.preview.ts", { eager: true });

Each package opts in with a one-line file outside src/. Stories stop importing the decorator entirely. Add /// <reference types="vite/client" /> at the top of preview.ts for the ImportMeta.glob typing, and add ../packages/*/storybook.preview.ts to the storybook tsconfig include so ESLint can resolve it.

Comment thread .storybook/tsconfig.json
"rootDir": ".."
},
"include": ["*.ts", "themes/**/*.ts"],
"exclude": ["node_modules"]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed actually, TS already ignores this folder

Actually I think this all can be like this now:

{
	"extends": "../packages/tsconfig.packages.json",
	"include": ["*.ts", "themes/**/*.ts"]
}

Verified: tsc --noEmit -p .storybook passes and pnpm storybook:build builds clean.

Comment thread .storybook/preview.ts
{
id: "root",
style: {
fontFamily: getDefaultFontStack(),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an issue with how this is used actually, style={{ fontFamily }} on #root is overridden by descendants like packages/tasks/src/index.css:8 that read var(--vscode-font-family) directly.

Set it as a CSS variable instead (extend the theme arrays or call setProperty next to the theme loop), then drop the inline style.

Comment thread package.json
"prettier": "^3.8.3",
"react": "catalog:",
"react-dom": "catalog:",
"storybook": "^8.6.18",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the most recent version for all of these new packages?

Comment on lines +25 to +29
tasks: [
task({ id: "task-1" }),
task({ id: "task-2" }),
task({ id: "task-3" }),
],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is reused 3 times here. Lift to a module-scope const or push into meta.args, then per-story args only overrides what differs.

Comment on lines +20 to +32
isThinking: false,
taskLogs: {
status: "ok",
logs: [
logEntry({
id: 1,
type: "input",
content: "What is the weather today?",
}),
logEntry({
id: 2,
type: "output",
content: "The weather today is sunny with a high of 25°C.",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is reused 2 times here. Lift to a module-scope const or push into meta.args, then per-story args only overrides what differs.

export const Opened: Story = {
play: async ({ canvasElement }) => {
const icon = canvasElement.querySelector("vscode-icon[action-icon]");
await expect(icon).toBeTruthy();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed IMO

Comment on lines +16 to +18
export const Default: Story = {
args: {},
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

args: {} is dead weight. Use Default: Story = {}; like in NoTemplateState.stories.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants